package com.wh.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wh.common.ApiRestResponse;
import com.wh.common.Constant;
import com.wh.config.RedisCache;
import com.wh.exception.SytException;
import com.wh.exception.SytExceptionEnum;
import com.wh.mapper.UserMapper;
import com.wh.model.dto.UserLoginDto;
import com.wh.model.pojo.User;
import com.wh.model.vo.UserLoginVo;
import com.wh.model.vo.UserRegisterVo;
import com.wh.service.UserService;
import com.wh.util.JwtUtil;
import com.wh.util.MD5Utils;
import com.wh.util.RandomNum;
import com.wh.util.RedisUtil;
import io.jsonwebtoken.Claims;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.security.NoSuchAlgorithmException;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author: wh(1835734390 @ qq.com)
 * @date: 2022/11/15 21:40
 * @description:
 * @version:
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper,User> implements UserService {
    @Autowired
    private UserMapper userMapper;
    @Autowired
    RedisUtil redisUtil;
    @Override
    public void register(UserRegisterVo userRegisterVo) {
        String account = userRegisterVo.getAccount();
        //查询用户名是否存在，不允许重名
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getAccount,account);
        Integer count = userMapper.selectCount(queryWrapper);
        if (count != 0){
            throw new SytException(SytExceptionEnum.NEED_OTHER_NAME);
        }
        //查询手机号是否已经注册过，不允许一个手机号重复注册
        LambdaQueryWrapper<User> queryWrapper2 = new LambdaQueryWrapper<>();
        queryWrapper2.eq(User::getMobile,userRegisterVo.getMobile());
        Integer count2 = userMapper.selectCount(queryWrapper2);
        if (count2 != 0){
            throw new SytException(SytExceptionEnum.NEED_OTHER_MOBILE);
        }
        User user = new User();
        BeanUtils.copyProperties(userRegisterVo,user);
        //设置用户为普通用户
        user.setUserType("1");
        //设置用户状态为正常
        user.setStatus("0");
        //使用UUID生成8位随机数
        user.setId(RandomNum.randomId());
        //使用MD5加密算法对密码进行加密
        String password = userRegisterVo.getPassword();
        try {
            user.setPassword(MD5Utils.getMD5Str(password));
        } catch (Exception e) {
            e.printStackTrace();
        }
        int insertNum = userMapper.insert(user);
        if (insertNum == 0){
            throw new SytException(SytExceptionEnum.INSERT_FAILED);
        }
    }

    @Override
    public ApiRestResponse login(UserLoginVo userLoginVo) {
        String md5Password = null;
        try {
            md5Password  = MD5Utils.getMD5Str(userLoginVo.getPassword());
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getMobile,userLoginVo.getMobile());
        if(userMapper.selectCount(queryWrapper) == 0){
            throw new SytException(SytExceptionEnum.NEED_MOBILE);
        }
        queryWrapper.eq(User::getPassword,md5Password);
        User user = userMapper.selectOne(queryWrapper);
        if (user.equals(null)){
            throw new SytException(SytExceptionEnum.WRONG_PASSWORD);
        }else if(user.getStatus().equals("1")){
            throw new SytException(SytExceptionEnum.WRONG_STATUS);
        }
        String id = user.getId();
        //使用userId来生成token access_token
        String jwtToken = JwtUtil.createJWT(id, Constant.ACCTOKEN_EXPIRE_TIME * 1000);
        //生成refresh token
        String refreshToken = JwtUtil.createJWT(id, Constant.RETOKEN_EXPIRE_TIME * 1000);

        // 把refreshToken存放到redis数据库中
        redisUtil.set(id,refreshToken,Constant.RETOKEN_EXPIRE_TIME);
        UserLoginDto userLoginDto = new UserLoginDto();
        BeanUtils.copyProperties(user,userLoginDto);
        userLoginDto.setMobile(RandomNum.blurPhone(user.getMobile()));
        userLoginDto.setToken(jwtToken);
        userLoginDto.setRefreshToken(refreshToken);
        return ApiRestResponse.success(10000,"登录成功",userLoginDto);
    }

    @Override
    public String refreshAccessToken(String refreshToken) {
        //对refreshToken进行解析，判断是否过期
        Claims claims = null;
        try {
            claims = JwtUtil.parseJWT(refreshToken);
        } catch (Exception e) {
            throw new SytException(SytExceptionEnum.NEED_RELOGIN);
        }
        // 没过期则生成一个新的token返回给前端
        String jwtToken = JwtUtil.createJWT(claims.getSubject(), Constant.ACCTOKEN_EXPIRE_TIME);
         /**同时也可以在刷新短期令牌的时候对refreshToken进行一个刷新
         *此时需要给前台发短期令牌的同时也发一个长期令牌
         *而且此时必须要对数据库的长期令牌进行更新！！！
        return accessToken;*/
        return jwtToken;
    }


    public String test(String token) {
        String jwtToken = null;
        Long expire = 0L;
        //判断当前token是否过期，以及是否和redis中对应的reToken一致
     //   boolean verify = JwtUtil.verify(token);
        try {
            expire = JwtUtil.getExpire(token);
        } catch (Exception e) {
            throw new SytException(SytExceptionEnum.TOKEN_FAILD);
        }
        //如果当前token过期，则从redis查询对应的reToken信息进行刷新
        if (System.currentTimeMillis() > expire){
            String userId = JwtUtil.getJti(token);
            Object object = redisUtil.get(userId);
            if (object.equals(null)){
                throw new SytException(SytExceptionEnum.TOKEN_FAILD);
            }else {
                //解析reToken是否过期，如果过期则需要清除redis缓存,然后要求重新登录。没有过期则利用reToken再次生成access_token
                Long expireTime = JwtUtil.getExpire(object.toString());
                if(System.currentTimeMillis() > expireTime){
                    throw new SytException(SytExceptionEnum.NEED_RELOGIN);
                }
                //刷新access_Token
                jwtToken = JwtUtil.createJWT(userId, Constant.ACCTOKEN_EXPIRE_TIME * 1000);
                //刷新redis中reToken的过期时间
                redisUtil.set(userId,(String)object,Constant.RETOKEN_EXPIRE_TIME);
                System.out.println(jwtToken);
                return jwtToken;
            }
        }
        return jwtToken;
    }
}
